#-------------------------------------------------------------------------------
# Name:        vsc
# Purpose:
#
# Author:      SUPER_紫电  QQ,911344755
#
# Created:     08/09/2022
# Copyright:   (c) SUPER_紫电 2022 All rights reserved.
# Licence:     <Modified BSD License>
#-------------------------------------------------------------------------------

import common, taskfile, vsctype
import familyid as family
from taskfile import *
from vsctype import *
from errcode import *

def bit(bit, value):
    buffer = bytearray(64)
    data = value
    for i in range(64):
        buffer[i] = data & 1
        data >>= 1
    return buffer[bit] == 1

def vscon():
    #return ata_cmd(0x45, 0, 0, 0x44, 0x57, 0x80)
    dev = ata_reg['dev']['value']
    outp(ata_reg['fe'  ]['address'], 0x45)
    outp(ata_reg['sc'  ]['address'], 0)
    outp(ata_reg['low' ]['address'], 0)
    outp(ata_reg['mid' ]['address'], 0x44)
    outp(ata_reg['high']['address'], 0x57)
    outp(ata_reg['dev' ]['address'], dev)
    outp(ata_reg['cmd' ]['address'], 0x80)
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def vscoff():
    return ata_cmd(0x44, 0, 0, 0x44, 0x57, 0x80)

def smart_read_log(sc, key):
    #if not ata_cmd(0xD5, sc, key, 0x4F, 0xC2, 0xB0):
    #    return False
    dev = ata_reg['dev']['value']
    outp(ata_reg['fe'  ]['address'], 0xD5)
    outp(ata_reg['sc'  ]['address'], sc)
    outp(ata_reg['low' ]['address'], key)
    outp(ata_reg['mid' ]['address'], 0x4F)
    outp(ata_reg['high']['address'], 0xC2)
    outp(ata_reg['dev' ]['address'], dev)
    outp(ata_reg['cmd' ]['address'], 0xB0)
    if not wait_not_busy(10):
        return False
    if not rstat_bitclr(0):
        return False
    return check_drq()

def smart_write_log(sc, key):
    #if not ata_cmd(0xD6, sc, key, 0x4F, 0xC2, 0xB0):
    #    return False
    dev = ata_reg['dev']['value']
    outp(ata_reg['fe'  ]['address'], 0xD6)
    outp(ata_reg['sc'  ]['address'], sc)
    outp(ata_reg['low' ]['address'], key)
    outp(ata_reg['mid' ]['address'], 0x4F)
    outp(ata_reg['high']['address'], 0xC2)
    outp(ata_reg['dev' ]['address'], dev)
    outp(ata_reg['cmd' ]['address'], 0xB0)
    if not wait_not_busy(10):
        return False
    if not rstat_bitclr(0):
        return False
    return check_drq()

def smart_read_data(buffer, offset=0, count=0):
    if count == 0:
        count = len(buffer) // 512
    if count == 0:
        count = get_sectors()
    while count > 0:
        blk = 256 if count > 256 else count
        if not smart_read_log(blk, SMART_DATAKEY):
            return False
        if not ioeng.read_data(offset, blk, 10):
            return False
        if not wait_not_busy(10):
            return False
        if not read_shared_memory(buffer, offset, blk*512):
            return False
        offset += blk*512
        count -= blk
    return count == 0

def smart_write_data(buffer, offset=0, count=0):
    if count == 0:
        count = len(buffer) // 512
    while count > 0:
        blk = 256 if count > 256 else count
        if not smart_write_log(blk, SMART_DATAKEY):
            return False
        if not write_shared_memory(buffer, offset, blk*512):
            return False
        if not ioeng.write_data(offset, blk, 10):
            return False
        if not wait_not_busy(10):
            return False
        offset += blk*512
        count -= blk
    return count == 0

def get_vsc_status():
    if not smart_read_log(1, SMART_CTRLKEY):
        return False
    buffer = bytearray(512)
    if not read_data(buffer, 10):
        return False
    try:
        memset(addressof(vsctype.vsc_status), 0, sizeof(vsctype.vsc_status))
        memmove(byref(vsctype.vsc_status), byref(c_buffer(bytes(buffer))), len(buffer))
        vsctype.ext_err = vsctype.vsc_status.ExtErr
        return True
    except:
        return False

def dec_vsc_status():
    if not get_vsc_status():
        return 'Error executing command'
    vscstatus = vsctype.vsc_status
    result  = '\nVSC Status'
    result += '\n------------------------------------------------------------'
    result += '\nFormat Version                               = %d' % vscstatus.Ver
    result += '\nVSC Implementation, Minor                    = %d' % vscstatus.Minor
    result += '\nVSC Implementation, Major                    = %d' % vscstatus.Major
    result += '\nMax Action Code Supported                    = %d' % vscstatus.MaxActCode
    result += '\nLast Cmd Type                                = '
    cmd_type = vscstatus.LastCmdType
    if cmd_type == 0:
        result += '28-Bit ATA CMD'
    elif cmd_type == 1:
        result += '48-Bit ATA CMD'
    elif cmd_type == 2:
        result += 'VSC Key CMD'
    elif cmd_type == 3:
        result += 'VSC Data CMD'
    else:
        result += 'UnKnown Type'
    result += '\nLast Cmd Register                            = 0x%02X' % vscstatus.LastCmd
    result += '\nLast VSC Cmd Action Code                     = 0x%02X' % vscstatus.LastActCode
    result += '\n\nLast Feature Register                        = 0x%04X' % vscstatus.LastFeat
    result += '\nLast Sector Count Register                   = 0x%04X' % vscstatus.LastSC
    result += '\nLast Sector Number Register                  = 0x%04X' % vscstatus.LastSN
    result += '\nLast Cylinder Register                       = 0x%04X' % vscstatus.LastCyl
    result += '\nLast LBA High                                = 0x%04X' % vscstatus.LastLBAHigh
    result += '\nLast Device Control Register                 = 0x%02X' % vscstatus.DevCtrl
    result += '\nLast Device/head Register                    = 0x%02X' % vscstatus.DevHd
    result += '\nLast Task File Response                      = 0x%04X' % vscstatus.LastResp
    result += '\n\nExtended Error                               = 0x%04X' % vscstatus.ExtErr
    result += '\nExtended Error Description                   = ' + dec_err_code()
    result += '\nSecondary Error Code                         = 0x%04X' % vscstatus.SecondaryEcode
    result += '\nHost Connection Speed                        = '
    connect_speed = vscstatus.ConnectSpeed
    if connect_speed == 0:
        result += 'NOT SUPPORTED'
    elif connect_speed == 1:
        result += 'PATA'
    elif connect_speed == 2:
        result += 'SATA GEN1'
    elif connect_speed == 3:
        result += 'SATA GEN2'
    elif connect_speed == 4:
        result += 'SATA GEN3'
    else:
        result += 'UNKNOWN SPEED'
    result += '\nAPM Level                                    = 0x%02X' % vscstatus.APMLevel
    vsctx = vscstatus.VSCTXCntLo + (vscstatus.VSCTXCntHi >> 32)
    result += '\n\nSectors Xfer Pending to/from drive           = %d (0x%012X)' % (vsctx, vsctx)
    result += '\nLast Task File Data                          = 0x%04X' % vscstatus.TFData
    #------ Display the Status Flags 1 ---------------------
    status_flg1 = vscstatus.StatusFlg1
    result += '\n\nStatus Flags 1= 0x%08X' % status_flg1
    result += '\n------------------------------------------------------------'
    result += '\nBit 0: VSC Command Set '
    result += 'Enabled' if bit(0, status_flg1) else 'Disabled'
    result += '\nBit 1: Smart is '
    result += 'Enabled' if bit(1, status_flg1) else 'Disabled'
    result += '\nBit 2: Legacy Native Mode '
    result += 'Supported' if bit(2, status_flg1) else 'Not Supported'
    result += '\nBit 3: Instability bit is '
    result += 'Set. FW Hard Reset recommended' if bit(3, status_flg1) else 'cleared'
    if bit(4, status_flg1):
        result += '\nBit 4: Pending VSC Tx from Drive to Host'
    else:
        result += '\nBit 4: No Pending VSC Tx from Drive to Host'
    if bit(5, status_flg1):
        result += '\nBit 5: VSC Command currently executing in background'
    else:
        result += '\nBit 5: No VSC Command currently executing in background'
    if bit(9, status_flg1):
        result += '\nBit 9: At least one DBS event occurred since the last clear DRM'
    else:
        result += '\nBit 9: No DBS event occurred since the last clear DRM'
    if bit(10, status_flg1):
        result += '\nBit 10: At least one reset-while-busy event occurred since the last clear DRM'
    else:
        result += '\nBit 10: No reset-while-busy event occurred since the last clear DRM'
    result += '\nBit 11: Drive is powered up in Standby and has not spun ... = '
    result += 'TRUE' if bit(11, status_flg1) else 'FALSE'
    result += '\nBit 13: Drive in Queue Abort Mode .... = '
    result += 'TRUE' if bit(13, status_flg1) else 'FALSE'
    result += '\nBit 16: VSC POR Reset Occurred ....... = '
    result += 'TRUE' if bit(16, status_flg1) else 'FALSE'
    result += '\nBit 17: Power On Reset Occurred ...... = '
    result += 'TRUE' if bit(17, status_flg1) else 'FALSE'
    result += '\nBit 18: Hardware Reset Occurred ...... = '
    result += 'TRUE' if bit(18, status_flg1) else 'FALSE'
    result += '\nBit 19: Software Reset Occurred ...... = '
    result += 'TRUE' if bit(19, status_flg1) else 'FALSE'
    result += '\nBit 20: Debug Stop Occurred .......... = '
    result += 'TRUE' if bit(20, status_flg1) else 'FALSE'
    result += '\nNote: Next Issue of VSC status will clear Bits 16 to 20 of Status 1 Flag'
    lvar1 = status_flg1 >> 26 & 3
    result += '\nBit 26 & 27: Drive Protect State (%1d) .......... = ' % lvar1
    if lvar1 == 0:
        result += 'UnLock'
    elif lvar1 == 1:
        result += 'Lock Count Down'
    elif lvar1 == 2:
        result += 'Lock'
    else:
        result += 'UnKnown'
    result += '\nBit 28: Encryption Key Loaded......... = '
    result += 'TRUE' if bit(28, status_flg1) else 'FALSE'
    pend_stat = (status_flg1 >> 30) & 3
    result += '\nBit 30-31: Offline Pending Status......... = 0x%X ' % pend_stat
    if pend_stat == 0:
        result += 'NO OL PENDING'
    elif pend_stat == 1:
        result += 'OL PENDING NORMAL MODE'
    elif pend_stat == 2:
        result += 'OL PENDING AGGRESSIVE MODE'
    elif pend_stat == 3:
        result += 'RESERVED'
    else:
        result += 'INVALID OL PENDING STATUS'
    # Current Drive State
    drv_state1 = {
        0: 'Idle',
        1: 'Standby',
        2: 'Sleep',
        3: 'Background DST',
        4: 'Background Data Lifeguard',
        5: 'Background VSC Command',
        6: 'PST test in progress',
    }
    cur_state = vscstatus.CurState
    result += '\n\nCurrent Drive State 1                        = %d %s' % (cur_state, drv_state1[cur_state])
    drv_state2 = {
        0: 'No DST or Smart OL',
        1: 'DST Quick Test',
        2: 'DST Extended Test',
        3: 'Conveyance Test',
        4: 'Selective Self Test',
        5: '(reserved)',
        6: '(reserved)',
        7: 'SmartOL Immediate (scan)',
        8: 'SmartOL Immediate (TA Margaining)',
        9: 'Smart Auto Offline (scan)',
        10: 'Smart Auto Offline (TA Margaining)',
        11: 'Smart Auto Offline (Selective)',
    }
    cur_state2 = vscstatus.CurState2
    result += '\nCurrent Drive State 2                        = 0x%02X ' % cur_state2
    result += '\n  ...BG DST/Smart OL State                   = '
    result += 'ACTIVE' if bit(0, cur_state2) else 'SUSPENDED'
    lvar1 = (cur_state2 >>1) & 0xF    # look at bit 1-4
    result += '\n  ...Test Type                               = '
    if lvar1 in drv_state2:
        result += drv_state2[lvar1]
    else:
        result += '  ...(reserved)'
    lvar1 = vscstatus.BGProgress
    result += '\n\nProgress Indicator                           =  %d' % (lvar1//10)
    lvar1 %= 10
    result += '.%d%%' % lvar1
    clba = vscstatus.CurLBA
    ulba = 0
    for i in range(6):
        ulba += (clba[5-i]<<((6-i)*8))
    result += '\n\nCurrent LBA                                  = 0x%08X' % ulba
    result += '\nCurrent Track Offset                         = 0x%04X' % vscstatus.CurTrkOft
    result += '\nVirtual cylinder of current active track     = 0x%08X' % vscstatus.CurVirCyl
    result += '\nVirtual head of current active track         = 0x%02X' % vscstatus.CurVirHd
    result += '\n\nFor VDT Drives Only:'
    result += '\nServo Track Offset of current active track   = 0x%04X' % vscstatus.CurCylOftSvo
    result += '\nVirt Servo Cylinder of current active track  = 0x%08X' % vscstatus.CurSvoCyl
    result += '\nData-to-Servo Conversion Offset              = 0x%04X' % vscstatus.CurSvoOft
    result += '\nCurrent Data Zone                            = 0x%02X' % vscstatus.CurZone
    result += '\nCurrent Wedge Start                          = 0x%04X' % vscstatus.CurWedgeStart
    result += '\nCurrent Wedge Size                           = 0x%04X' % vscstatus.CurWedgeSize
    result += '\n\nDrive Temperature (avg)                      = 0x%02X' % vscstatus.DTemp
    result += '\nJunction Temperature (degree)                = 0x%02X' % vscstatus.JTemp
    result += '\nFlex Temperature (degree)                    = 0x%02X' % vscstatus.FTemp
    result += '\nCoil Temperature                             = 0x%02X' % vscstatus.CTemp
    result += '\nServo Status                                 = 0x%04X' % vscstatus.SvStatus
    lvar1 = vscstatus.SeedCyl
    cyl = 0
    for i in range(3):
        cyl += (clba[2-i]<<((3-i)*8))
    result += '\nSeed Cyl                                     = 0x%06X' % cyl
    result += '\nSeed Head                                    = 0x%02X' % vscstatus.SeedHead
    result += '\nSeed Sector                                  = 0x%04X' % vscstatus.SeedSector
    result += '\nSector Skew                                  = 0x%04X' % vscstatus.SectorSkew
    result += '\nWedge Skew                                   = 0x%04X' % vscstatus.WedgeSkew
    result += '\n\nDebugstop Code                               = 0x%08X' % vscstatus.DBSCode
    result += '\nDebugstop Parameter                          = 0x%08X' % vscstatus.DBSPara
    #result += '\nDebugStop Code Description                   = %s' %
    result += '\n\nWrite Fault Occurred                         = '
    result += 'TRUE' if bit(25, status_flg1) else 'FALSE'
    result += '\nWrite Fault LBA                              = 0x%04X' % vscstatus.WrFaultLBAHigh
    result += '\n\nPST Information'
    result += '\n------------------------------------------------------------'
    result += '\nPTM File Id                                  = 0x%04X' % vscstatus.PTMId
    result += '\nPTM Test Id                                  = 0x%04X' % vscstatus.TestId
    result += '\nCurrent VSC Command                          = 0x%04X' % vscstatus.ActionCode
    result += '\nExtended Error Code                          = 0x%04X' % vscstatus.ExtErr
    result += '\nExtended Error Description                   = ' + dec_err_code()
    result += '\n\nPTM Status:\n'
    action_status = vscstatus.ActionStatus
    for i in range(6):
        result += '0x%04X ' % action_status[i]
    return result

def vsc_status_ok():
    if not get_vsc_status():
        return False
    ext_err = vsctype.ext_err
    return ext_err == 0 or ext_err == 0xFFFF or ext_err == 0xC409

def get_err_code():
    vsctype.ext_err = inp(ata_reg['sc']['address']) + \
        (inp(ata_reg['low']['address']) << 8)
    return vsctype.ext_err

def dec_err_code():
    if vsctype.ext_err == 0:
        return 'SUCCESS'
    else:
        errcode = '0x%04X' % vsctype.ext_err
        if errcode in err_code:
            return errcode + ': ' + err_code[errcode]
        else:
            return errcode + ': ERROR_NOT_DEFINE'

def get_sectors():
    return inp(ata_reg['mid']['address'])+(inp(ata_reg['high']['address'])<<8)

def royl_checksum32(buffer):
    crc = 0
    buffer[12] = 0
    buffer[13] = 0
    buffer[14] = 0
    buffer[15] = 0
    r = len(buffer)
    for i in range(0, r, 4):
        crc -= struct.unpack_from('@L', buffer, i)[0]
    crc &= 0xFFFFFFFF
    buffer[12] = crc & 0xFF
    buffer[13] = crc >> 8 & 0xFF
    buffer[14] = crc >> 16 & 0xFF
    buffer[15] = crc >> 24
    return crc

def checksum16(buffer):
    crc = 0
    r = len(buffer)
    for i in range(0, r, 2):
        crc -= struct.unpack_from('@H', buffer, i)[0]
    crc &= 0xFFFF
    return crc

def checksum8(buffer):
    crc = 0
    r = len(buffer)
    for i in range(r):
        crc -= buffer[i]
    crc &= 0xFFFF
    return crc

def checksumA(buffer):
    crc = 0
    file_hdr_type = struct.unpack_from('@L', buffer, 0)[0]
    file_id = struct.unpack_from('@H', buffer, 8)[0]
    if file_hdr_type == 0x4C594F52 and file_id == 0xA:
        file_hdr_size = buffer[6]
        data_size = buffer[file_hdr_size]
        buffer[0x3C] = 0
        buffer[0x3D] = 0
        bitmap_data = bytearray(data_size)
        bitmap_data[0:data_size] = buffer[file_hdr_size:file_hdr_size+data_size]
        crc = checksum8(bitmap_data)
        buffer[0x3C] = crc & 0xFF
        buffer[0x3D] = crc >> 8
        royl_checksum32(buffer)
    return crc

def read_file(filename, buffer):
    try:
        with open(filename, 'rb') as file:
            while True:
                data = file.read(4)
                if not data:
                    break
                buffer.extend(struct.unpack('@4B', data))
        return True
    except:
        return False

def save_file(filename, buffer):
    try:
        with open(filename, 'wb') as file:
            file.write(buffer)
        return True
    except:
        return False

def royl_file_checksum(buffer):
    file_hdr_type = struct.unpack_from('@L', buffer, 0)[0]
    if file_hdr_type != 0x4C594F52:
        return
    file_size = struct.unpack_from('@H', buffer, 10)[0]
    if file_size != len(buffer) // 512:
        return
    royl_checksum32(buffer)

def ldbin(filename, checksum=True):
    vsctype.super_buffer.clear()
    if not read_file(filename, vsctype.super_buffer):
        return False
    if checksum:
        royl_file_checksum(vsctype.super_buffer)
    return True

def svbin(filename, checksum=False):
    if checksum:
        royl_file_checksum(vsctype.super_buffer)
    return save_file(filename, vsctype.super_buffer)

def zero_bytes(buffer, offset=0, size=0):
    if size == 0:
        size = len(buffer)
    for i in range(size):
        buffer[offset+i] = 0

def copy_bytes(buffer, source, size):
    for i in range(size):
        buffer[i] = source[i]

def write_vsc(key_sector):
    if not vscon():
        return False
    if not smart_write_log(1, SMART_CTRLKEY):
        return False
    buffer = bytearray(512)
    source = bytes((c_ubyte*sizeof(key_sector)).from_address(addressof(key_sector)),)
    copy_bytes(buffer,  source, sizeof(key_sector))
    return write_data(buffer, 10)

def send_vsc(key_sector, timeout=10):
    if not write_vsc(key_sector):
        return False
    if not wait_not_busy(timeout):
        return False
    return rstat_bitclr(0)

def vsc(action_code, param_list=[]):
    param = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    for i in range(len(param_list)):
        param[i] = param_list[i]
    key_sector = Key_Sector()
    key_sector.action_code = action_code
    key_sector.param1  = param[0]
    key_sector.param2  = param[1]
    key_sector.param3  = param[2]
    key_sector.param4  = param[3]
    key_sector.param5  = param[4]
    key_sector.param6  = param[5]
    key_sector.param7  = param[6]
    key_sector.param8  = param[7]
    key_sector.param9  = param[8]
    key_sector.param10 = param[9]
    key_sector.param11 = param[10]
    key_sector.param12 = param[11]
    key_sector.param13 = param[12]
    key_sector.param14 = param[13]
    key_sector.param15 = param[14]
    vsctype.ext_err = 0 if send_vsc(key_sector, 10) else get_err_code()
    return vsctype.ext_err

def xfile(func_code, file_id, test_id, param_list=[]):
    param = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    for i in range(len(param_list)):
        param[i] = param_list[i]
    xfile_key_sector = XFile_Key_Sector()
    xfile_key_sector.action_code = AC_EXECFILE
    xfile_key_sector.func_code   = func_code
    xfile_key_sector.file_id     = file_id
    xfile_key_sector.test_id     = test_id
    xfile_key_sector.test_param1  = param[0]
    xfile_key_sector.test_param2  = param[1]
    xfile_key_sector.test_param3  = param[2]
    xfile_key_sector.test_param4  = param[3]
    xfile_key_sector.test_param5  = param[4]
    xfile_key_sector.test_param6  = param[5]
    xfile_key_sector.test_param7  = param[6]
    xfile_key_sector.test_param8  = param[7]
    xfile_key_sector.test_param9  = param[8]
    xfile_key_sector.test_param10 = param[9]
    xfile_key_sector.test_param11 = param[10]
    xfile_key_sector.test_param12 = param[11]
    xfile_key_sector.test_param13 = param[12]
    xfile_key_sector.test_param14 = param[13]
    xfile_key_sector.test_param15 = param[14]
    xfile_key_sector.test_param16 = param[15]
    vsctype.ext_err = 0 if send_vsc(xfile_key_sector, 10) else get_err_code()
    return vsctype.ext_err

def xpst(file_id, test_id, param_list=[]):
    func_code = FC_ExecFile.eExecPST.value
    return xfile(func_code ,file_id, test_id, param_list)

def xcap(file_id, test_id, param_list=[]):
    func_code = FC_ExecFile.eExecCaptive.value
    return xfile(func_code, file_id, test_id, param_list)

def init_download_ptm(file_id, pack_size):
    func_code = FC_ExecFile.eInitDownloadCodePTM.value
    test_id = 0
    param_list = [pack_size & 0xFFFF, pack_size & 0xFFFF0000]
    return xfile(func_code, file_id, test_id, param_list)

def rw_bufex(func_code, start_offset, blk_cnt):
    action_code = AC_RDWRBUFEXT
    param_list = [
        func_code,
        start_offset & 0xFFFF,
        start_offset >> 16,
        blk_cnt & 0xFFFF,
        blk_cnt >> 16
    ]
    return vsc(action_code, param_list)

# load 10/13
def wbx_covl(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eWBX_COVL.value
    return rw_bufex(func_code, start_offset, blk_cnt)

# load 5c
def wbx_sovl(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eWBX_SOVL.value
    return rw_bufex(func_code, start_offset, blk_cnt)

# load 11
def wbx_povl(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eWBX_PERMOVL.value
    return rw_bufex(func_code, start_offset, blk_cnt)

# load 1b
def wbx_tovl(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eWBX_TRANSOVL.value
    return rw_bufex(func_code, start_offset, blk_cnt)

# load 80
def wrmem(start_offset, bytes_cnt):
    action_code = AC_RDWRMEM
    func_code = FC_RWMem.eWRMEM.value
    param_list = [
        func_code,
        start_offset & 0xFFFF,
        start_offset >> 16,
        bytes_cnt & 0xFFFF,
        bytes_cnt >> 16
    ]
    return vsc(action_code, param_list)

def ld10(file_path):
    file_path += '\\10.rpm'
    if not ldbin(file_path):
        return False
    blk_cnt = len(vsctype.super_buffer) // 512
    if wbx_covl(0, blk_cnt) != 0:
        return vsctype.ext_err == 0xB095
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def ld5c(file_path):
    file_path += '\\5c.rpm'
    if not ldbin(file_path):
        return False
    blk_cnt = len(vsctype.super_buffer) // 512
    if wbx_sovl(0, blk_cnt) != 0:
        return vsctype.ext_err == 0xB094
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def ld11(file_path):
    file_path += '\\11.rpm'
    if not ldbin(file_path):
        return False
    blk_cnt = len(vsctype.super_buffer) // 512
    if wbx_povl(0, blk_cnt) != 0:
        return vsctype.ext_err == 0x3041 or vsctype.ext_err == 0x3900
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def ld13(file_path):
    file_path += '\\13.rpm'
    if not ldbin(file_path):
        return False
    blk_cnt = len(vsctype.super_buffer) // 512
    if wbx_covl(0, blk_cnt) != 0:
        return vsctype.ext_err == 0xB095 or vsctype.ext_err == 0xB0B1
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def ld80(file_path):
    file_path += '\\80.rpm'
    if not ldbin(file_path):
        return False
    start_offset = struct.unpack_from('@L', vsctype.super_buffer, 0x38)[0]
    bytes_cnt = len(vsctype.super_buffer)
    if wrmem(start_offset, bytes_cnt) != 0:
        return vsctype.ext_err == 0xB095
    if not smart_write_data(vsctype.super_buffer, 0, bytes_cnt // 512):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def ld1b(file_path):
    file_path += '\\1b.rpm'
    if not ldbin(file_path):
        return False
    blk_cnt = len(vsctype.super_buffer) // 512
    if wbx_tovl(0, blk_cnt) != 0:
        return vsctype.ext_err == 0x3901
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

# load 10 5c 11 13 80 1b
def ldovl(file_path):
    filename = file_path + '\\11.rpm'
    if not os.path.exists(filename):
        return False
    actions = [
        {'file': '10', 'fun': ld10, 'des': 'Load Cache Overlay(0x10)'},
        {'file': '5c', 'fun': ld5c, 'des': 'Load Servo Overlay(0x5C)'},
        {'file': '11', 'fun': ld11, 'des': 'Load Permanent Overlay(0x11)'},
        {'file': '13', 'fun': ld13, 'des': 'Load Cache Overlay(0x13)'},
        {'file': '80', 'fun': ld80, 'des': 'Load Overlay File(0x80)'},
        {'file': '1b', 'fun': ld1b, 'des': 'Load Transient Overlay(0x1B)'},
    ]
    result = False
    for i in range(len(actions)):
        file_id = actions[i]['file']
        if os.path.exists(file_path + '\\' + file_id + '.rpm'):
            result = actions[i]['fun'](file_path)
            if not result:
                break
    return result

def rbx_pst(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eRBX_PST.value
    if rw_bufex(func_code, start_offset, blk_cnt) != 0:
        return False
    if not smart_read_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    return rstat_bitclr(0)

def rbx_pst_data(start_offset, blk_cnt):
    func_code = FC_RWBufEx.eRBX_PST_DATA.value
    if rw_bufex(func_code, start_offset, blk_cnt) != 0:
        return False
    if not smart_read_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    return rstat_bitclr(0)

def wbx_pst(file_path, file_id, start_offset):
    filename = '%s\\%X.rpm' % (file_path, file_id)
    if not ldbin(filename):
        return False
    func_code = FC_RWBufEx.eWBX_PST.value
    blk_cnt = len(vsctype.super_buffer) // 512
    if rw_bufex(func_code, start_offset, blk_cnt) != 0:
        return False
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    return rstat_bitclr(0)

def wbx_pst_data(file_path, file_id, start_offset):
    filename = '%s\\%X.rpm' % (file_path, file_id)
    if not ldbin(filename):
        return False
    func_code = FC_RWBufEx.eWBX_PST_DATA.value
    blk_cnt = len(vsctype.super_buffer) // 512
    if rw_bufex(func_code, start_offset, blk_cnt) != 0:
        return False
    if not smart_write_data(vsctype.super_buffer, 0, blk_cnt):
        return False
    return rstat_bitclr(0)

def mini_test(file_path, file_id, test_id):
    if not ldovl(file_path):
        return False
    if not wbx_pst(file_path, file_id, 0):
        return False
    if xpst(file_id, test_id) != 0:
        return False
    return rstat_bitclr(0)

def mini_cal(file_path):
    return mini_test(file_path, 0xB1, 0x4E0)

def seam_cal(file_path):
    return mini_test(file_path, 0xB1, 0x160)

def mini_wrro(file_path, test_id=0):
    return mini_test(file_path, 0xB2, test_id)

def mini_wrro2(file_path):
    return mini_wrro(file_path, 2)

def mini_ibi(file_path):
    return mini_test(file_path, 0xDF, 1)

def mini_arco(file_path , head_dcm, media_dcm):
    if not ldovl(file_path):
        return False
    file_id = 0x2401 if os.path.exists(file_path + '\\2401.rpm') else 0xC4
    if not wbx_pst(file_path, file_id, 0):
        return False
    filename = file_path + '\\C5.rpm'
    if not ldbin(filename):
        return False
    b = vsctype.super_buffer[0x24]
    start_offset = 512
    if b == 0: start_offset = 256
    if b == 2: start_offset = 512
    if b == 3: start_offset = 640
    if b == 4:
        b = vsctype.super_buffer[0x23]
        if b == 0x00: start_offset = 0x300
        if b == 0x50: start_offset = 808
        if b == 0xD0: start_offset = 872
        if b == 0xE0: start_offset = 880
        if b == 0xF0: start_offset = 888
        if b == 0xF8: start_offset = 892
    if b == 5:
        b = vsctype.super_buffer[0x23]
        if b == 0x84: start_offset = 962
        if b == 0xC0: start_offset = 992
        if b == 0xE0: start_offset = 1008
    if not wbx_pst(file_path, 0xC5, start_offset):
        return False
    if xpst(file_id, 1, [0x44, 0x19, head_dcm, media_dcm]) != 0:
        return False
    return rstat_bitclr(0)

def mini_arco_test(file_path):
    head_dcm, media_dcm = 0, 0
    if rdfl(0xA):
        hdr_size  = vsctype.super_buffer[6]
        head_dcm  = vsctype.super_buffer[hdr_size+13]
        media_dcm = vsctype.super_buffer[hdr_size+12]
    if head_dcm == 0 or media_dcm == 0:
        if not ldbin(file_path + '\\28.rpm'):
            return False
        head_dcm  = vsctype.super_buffer[0x44]
        media_dcm = vsctype.super_buffer[0x48]
    return mini_arco(file_path, head_dcm, media_dcm)

# Download Microcode (PTM)
def download_ptm(filename):
    if not ldbin(filename):
        return False
    file_size = len(vsctype.super_buffer)
    if init_download_ptm(0x108, file_size) != 0:
        return False
    if not smart_write_data(vsctype.super_buffer, 0, file_size//512):
        return False
    return rstat_bitclr(0)

def download_packets(file_path):
    cf1 = ''
    packet_type = ['cf', 'ce', 'ib', 'rc', 'rd', 'se', 'sl', '115']
    packet_list = []
    for file in os.listdir(file_path):
        if file.endswith('.cf1'):
            cf1 = file
        else:
            if file[-3:-1] in packet_type or file.endswith('.115'):
                packet_list.append(file)
    if cf1 == '':
        return False
    if not download_ptm(cf1):
        return False
    if not spindown_reset():
        return False
    if not wait_not_busy(30):
        return False
    #init2(False)
    zero_size(2)
    if not ldovl(file_path):
        return False
    for packet_name in packet_list:
        if not download_ptm(packet_name):
            return False
    #init2(True)
    fix_size(2)
    return rstat_bitclr(0)

# Down Load Static File
def download_stfl(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eDNSTATICFILE.value
    key_sector.param2 = file_id
    return send_vsc(key_sector)

# Up Load Static File
def upload_stfl(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eUPSTATICFILE.value
    key_sector.param2 = file_id
    return send_vsc(key_sector)

def get_drv_fmt(drv_fmt=0):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = RD_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eDriveFormat.value
    if not send_vsc(key_sector):
        return False
    drv_fmt = inp(ata_reg['sc']['address'])
    return True

def get_zone_spt(vir_head):
    if rdchs(-1, vir_head, 1, 0) != 0:
        return 0
    return get_sectors()

def get_phys_zone_data(vir_head):
    key_sector = Key_Sector()
    key_sector.action_code = AC_GETDRVTBL
    key_sector.param1 = FC_GetDrvTbl.ePhysZoneTbl.value
    key_sector.param2 = vir_head
    if not send_vsc(key_sector):
        return False
    sectors = get_sectors()
    if sectors == 0:
        return False
    vsctype.super_buffer = bytearray(sectors * 512)
    if not smart_read_data(vsctype.super_buffer, 0, sectors):
        return False
    return rstat_bitclr(0)

def get_phys_zone_spt(vir_head):
    vsctype.super_buffer.clear()
    if not get_phys_zone_data(vir_head):
        return 0
    return struct.unpack_from('@H', vsctype.super_buffer, 66)[0]

def get_phys_zone_tbl(vir_head):
    pys_zone_tbl_hdr = Sect_Phys_Zone_Tbl_Hdr()
    entry_list = []
    if get_phys_zone_data(vir_head):
        buffer = c_buffer(bytes(vsctype.super_buffer))
        header_size = sizeof(pys_zone_tbl_hdr) # 50
        memmove(byref(pys_zone_tbl_hdr), byref(buffer), header_size)
        num_zones = pys_zone_tbl_hdr.num_zones
        entry_start = header_size
        for i in range(num_zones):
            pys_zone_tbl = Sect_Phys_Zone_Tbl()
            memmove(byref(pys_zone_tbl), byref(buffer, entry_start), sizeof(pys_zone_tbl))
            entry_list.append(pys_zone_tbl)
            entry_start += sizeof(pys_zone_tbl) # 18
    return pys_zone_tbl_hdr, entry_list

def get_vir_hd():
    drv_data_tbl = Drv_Data_Tbl()
    get_drv_tbl_data(drv_data_tbl)
    return drv_data_tbl.VirHdCnt

def get_drv_tbl():
    drv_data_tbl = Drv_Data_Tbl()
    if not get_drv_tbl_data(drv_data_tbl):
        return ''
    return dec_drv_tbl(drv_data_tbl)

def get_drv_tbl_data(drv_tbl):
    key_sector = Key_Sector()
    key_sector.action_code = AC_GETDRVTBL
    key_sector.param1 = FC_GetDrvTbl.eDrvTbl.value
    if not send_vsc(key_sector):
        return False
    sectors = get_sectors()
    if sectors == 0:
        return False
    buffer = bytearray(sectors * 512)
    if not smart_read_data(buffer, 0, sectors):
        return False
    memset(addressof(drv_tbl), 0, sizeof(drv_tbl))
    memmove(byref(drv_tbl), byref(c_buffer(bytes(buffer))), sizeof(drv_tbl))
    return True

def dec_drv_tbl(drv_tbl):
    result = '\nDrive Data Tables'
    result += '\n=================================================='
    result += '\n Format Version ..... = %d' % drv_tbl.Ver
    ctl_fwrev = ''
    for i in range(8):
        ctl_fwrev += chr(drv_tbl.CtrlFWRev[i])
    ctl_fwrev = ctl_fwrev.rstrip('\x00')
    result += '\n Controller FW Rev .. = ' + ctl_fwrev
    srv_fwrev = ''
    for i in range(8):
        srv_fwrev += chr(drv_tbl.ServoFWRev[i])
    result += '\n Servo FW Rev ....... = ' + srv_fwrev
    ovl_fwrev = ''
    for i in range(8):
        ovl_fwrev += chr(drv_tbl.OvlFWRev[i])
    result += '\n Overlay FW Rev ..... = ' + ovl_fwrev
    drv_type = drv_tbl.DrvType
    result += '\n Drive Type ......... = %d ' % drv_type
    if drv_type == 0:
        result += '(Desktop 3.5 Inch)'
    elif drv_type == 1:
        result += '(Enterprise 3.5 Inch)'
    elif drv_type == 2:
        result += '(DeskTop 2.5 Inch)'
    elif drv_type == 3:
        result += '(Mobile 2.5 Inch)'
    elif drv_type == 4:
        result += '(Mobile 1.8 inch)'
    elif drv_type == 5:
        result += '(Mobile 1.0 inch)'
    elif drv_type == 6:
        result += '(Enterprise 2.5 inch)'
    model = ''
    for i in range(40):
        model += chr(drv_tbl.ModelNumber[i])
    model = model.strip().rstrip('\x00')
    result += '\n Model Number ....... = ' + model
    serial = ''
    for i in range(20):
        serial += chr(drv_tbl.SerialNumber[i])
    serial = serial.strip().rstrip('\x00')
    result += '\n Serial Number ...... = ' + serial
    result += '\n\nDrive Build Information'
    result += '\n--------------------------------------------------'
    result += '\n Product ID ......... = 0x%04X' % drv_tbl.ProdID
    result += '\n Product ID 16 Bit .. = 0x%04X' % drv_tbl.ProdID16
    result += '\n Globle Product ID .. = 0x%04X' % drv_tbl.GlobProdID
    '''
    family_id = drv_tbl.ProdID & 0xFF
    if family_id == 0xFE:
        family_id = drv_tbl.ProdID16
        result +=  '\n Family ID .......... = 0x%04X' % family_id
    else:
        result +=  '\n Family ID .......... = 0x%02X' % family_id
    '''
    family_id, family_name = family.get_family_name(
        drv_tbl.ProdID, drv_tbl.ProdID16,drv_tbl.GlobProdID)
    result +=  '\n Family ID .......... = 0x%04X (%s)' % (family_id, family_name)
    result += '\n DRAM Size .......... = %d MB' % drv_tbl.DRAMSize
    result += '\n Drive Platter Count. = %d' % drv_tbl.PlatCnt
    result += '\n No. Of Physical Hds. = %d (Including Depops)' % drv_tbl.PhyHdCnt
    result += '\n No. Of Virtual Hds.. = %d' % drv_tbl.VirHdCnt
    bitmap_des = '(bit 0 = head 0. bit set = head used)'
    result += '\n Depop Bit Map (Hex). = 0x%02X %s' % (drv_tbl.Depops, bitmap_des)
    result += '\n No. Of Zones ....... = %d' % drv_tbl.ZoneCnt
    result += '\n No. Of Servo Wedges. = %d' % drv_tbl.ServoCnt
    result += '\n No. Of Neg. Cyls ... = %d' % drv_tbl.RsvdCylCnt
    result += '\n Spindle RPM ........ = %d' % drv_tbl.SpindleRPM
    result += '\n Phy. No Of User Cyls = %d' % drv_tbl.UserCylCnt
    result += '\n Cylinder Wedge Skew. = %d' % drv_tbl.CylWedgeSkew
    result += '\n Head Skew .......... = %d' % drv_tbl.HdWedgeSkew
    result += '\n Cluster Skew ....... = %d' % drv_tbl.ClusterSkew
    result += '\n Rom Type ........... = %d ' % drv_tbl.CodeRes
    rom_type = drv_tbl.CodeRes
    if rom_type == 1:
        result += '(ROM OTP)'
    elif rom_type == 2:
        result += '(ROM CUSTOM OTP)'
    elif rom_type == 3:
        result += '(Parallel Flash)'
    elif rom_type == 4:
        result += '(Custom Flash)'
    elif rom_type == 5:
        result += '(Serial Flash)'
    elif rom_type == 6:
        result += '(Manteca)'
    else:
        result += '(Unknown)'
    result += '\n Flash Size ......... = %d KB' % (drv_tbl.FlashSize * 16)
    result += '\n PCBA Type .......... = %d ' % drv_tbl.PCBAType
    pcb_type = drv_tbl.PCBAType
    if pcb_type == 0:
        result += '(Entek)'
    elif pcb_type == 1:
        result += '(Non Entek)'
    else:
        result += '(UnKnown)'
    result += '\n PCBA Revision ...... = %d' % drv_tbl.PCBARev
    result += '\n Interface Type ..... = %d ' % drv_tbl.InterfaceTyp
    interface_type = drv_tbl.InterfaceTyp
    if interface_type == 0:
        result += '(UnKnown)'
    elif interface_type == 1:
        result += '(Parallel ATA)'
    elif interface_type == 2:
        result += '(Serial ATA)'
    elif interface_type == 3:
        result += '(USB)'
    elif interface_type == 4:
        result += '(Fiber Channel)'
    elif interface_type == 5:
        result += '(SAS)'
    elif interface_type == 6:
        result += '(CFA)'
    else:
        result += '(UnKnown)'
    result += '\n\nDrive Parts Information'
    result += '\n--------------------------------------------------'
    result += '\n Ctrl Chip Vendor ... = 0x%X' % drv_tbl.CtlrChipVend
    result += '\n Ctrl Chip Rev ...... = 0x%X' % drv_tbl.CtrlChipRev
    result += '\n MicroP Vendor ...... = 0x%X' % drv_tbl.UpVend
    result += '\n MicroP Rev ......... = 0x%X' % drv_tbl.UpRev
    result += '\n Channel Chip Vendor. = 0x%X' % drv_tbl.ChnChipVend
    result += '\n Channel Chip Rev.... = 0x%X' % drv_tbl.ChnChipRev
    result += '\n Preamp Vendor ...... = 0x%X' % drv_tbl.PreampVend
    result += '\n Preamp Rev ......... = 0x%X' % drv_tbl.PreampRev
    result += '\n PowerIC Vendor ..... = 0x%X' % drv_tbl.PwrICVend
    result += '\n PowerIC Rev ........ = 0x%X' % drv_tbl.PwrICRev
    result += '\n\nError Correction Information'
    result += '\n--------------------------------------------------'
    result += '\n No. Of Interleaves ......... = %d' % drv_tbl.OTFIntlv
    result += '\n OTF Corr. Span In Bytes .... = %d' % drv_tbl.NumOTF
    result += '\n Max FW Corr. Span In Bytes.. = %d' % drv_tbl.BurstCnt
    ecc_bytes = drv_tbl.ECCBytes[0] + drv_tbl.ECCBytes[1]
    result += '\n No. Of ECC Bytes + CRC Bytes = %d' % ecc_bytes
    result += '\n Feature Flags .............. = 0x%X' % drv_tbl.FeatureFlags
    jmp_set = drv_tbl.JumperSet
    result += '\n\nJumper Settings'
    result += '\n--------------------------------------------------'
    result += '\n Jumper Setting Value..... = 0x%X' % jmp_set
    result += '\n Bit 0 (Master Jumper).... = '
    result += 'ON' if jmp_set & 1 else 'OFF'
    result += '\n Bit 1 (Slave Jumper)..... = '
    result += 'ON' if jmp_set & 2 else 'OFF'
    result += '\n Bit 2 (CSEL Jumper)...... = '
    result += 'ON' if jmp_set & 4 else 'OFF'
    result += '\n\nReloList File Information'
    result += '\n--------------------------------------------------'
    result += '\n No. Of Relocations ................ = %d' % drv_tbl.ReloCnt
    result += '\n No. Of Tares....................... = %d' % drv_tbl.TareCnt
    result += '\n No. Of FTares ..................... = %d' % drv_tbl.FTareCnt
    result += '\n No. Of Possible Remaining Relos ... = %d' % drv_tbl.RemRelo
    result += '\n No. Of Consumed Spares............. = %d' % drv_tbl.ConsumedSpare
    result += '\n Last LBA Of Spare Pool............. = 0x%X' % drv_tbl.LastSpareLBALow
    result += '\n\nDrive Format Information'
    result += '\n--------------------------------------------------'
    result += '\n Tracks Per Inch (In KTPI)............ = %d' % drv_tbl.TPI
    result += '\n Area Density In 100MB (Per Platter).. = %d' % drv_tbl.AreaDensity
    result += '\n Format Type.......................... = %d' % drv_tbl.FormatType
    if drv_tbl.FormatType == 0:
        result += ' (Primary Format)'
    else:
        result += ' (Alternate %d Format)' % drv_tbl.LastSpareLBALow
    result += '\n\nSATA IPM Timers'
    result += '\n--------------------------------------------------'
    result += '\n Partial................. = %5d ms' % drv_tbl.PartialTimer
    result += '\n Slumber................. = %5d ms' % drv_tbl.SlumberTimer
    result += '\n\nDrive Built Data'
    result += '\n--------------------------------------------------'
    dcm = ''
    for i in range(36):
        dcm += chr(drv_tbl.DrvDataTblOverlay.DCM[i])
    result += '\n DCM...................... : %s' % dcm
    fts_data, fts_rec_data = '', ''
    for i in range(12):
        fts_data += chr(drv_tbl.DrvDataTblOverlay.FTSDate[i])
        fts_rec_data += chr(drv_tbl.DrvDataTblOverlay.FTSReconfigDate[i])
    result += '\n FTS Date ................ : %s' % fts_data
    result += '\n FTS Reconfig Date........ : %s' % fts_rec_data
    pid = '%04X-%04X-%04X'%(drv_tbl.ProdID,drv_tbl.ProdID16,drv_tbl.GlobProdID)
    #common.workdir = pid + '\\' + model + '_' + ctl_fwrev + '_' + serial
    common.workdir = '{}\\{}_{}_{}'.format(pid, model, ctl_fwrev, serial)
    common.workdir = common.workdir.replace('\x00', '')
    return result

# Initiate Power On Reset
def reset_drive(func_code):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RESET
    key_sector.param1 = func_code
    return write_vsc(key_sector)

# Reset Drive Immediate
def immediate_reset():
    return reset_drive(FC_Reset.eIMMEDPOR.value)

# Spin Down And Reset Drive
def spindown_reset():
    return reset_drive(FC_Reset.eSPINDOWNPOR.value)

# Soft Reset
def warm_start():
    return reset_drive(FC_Reset.eWARMSTART.value)

# Servo Control Functions
def servo_control(func_code):
    key_sector = Key_Sector()
    key_sector.action_code = AC_SERVOCTRL
    key_sector.param1 = func_code
    return write_vsc(key_sector)

# Servo Spin Up
def sv_spinup():
    return servo_control(FC_ServoCtrl.ServoSpinUp.value)

# Servo Spin Down
def sv_spindn():
    if not servo_control(FC_ServoCtrl.ServoSpinDn.value):
        return False
    if not wait_not_busy(10):
        return False
    return rstat_bitclr(0)

def xfr_read():
    if rstat_bit(0):
        return False
    vsctype.super_buffer.clear()
    sectors = get_sectors()
    if sectors == 0:
        return False
    vsctype.super_buffer = bytearray(sectors * 512)
    if not smart_read_data(vsctype.super_buffer, 0, sectors):
        return False
    return rstat_bitclr(0)

def xfr_write():
    if rstat_bit(0):
        return False
    sectors = get_sectors()
    if sectors == 0:
        return False
    if not smart_write_data(vsctype.super_buffer, 0, sectors):
        return False
    return rstat_bitclr(0)

def chkresf(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_CHKFILEID
    key_sector.param1 = file_id
    timeout = 180 if file_id == 4 or file_id == 5 else 60
    if not write_vsc(key_sector):
        return False
    if not wait_not_busy(timeout):
        return False
    return rstat_bitclr(0)

def rdfl(file_id, count=0):
    result = False
    vsctype.super_buffer.clear()
    if vsc(8, [1, file_id]) == 0:
        if count==0:
            count = get_sectors()
        vsctype.super_buffer = bytearray(count * 512)
        result = smart_read_data(vsctype.super_buffer, 0, count)
    elif vsctype.ext_err == 0x3603 or vsctype.ext_err == 0x3712:
        result = prdfl(file_id)
    return result

def wrfl(file_id, count=0):
    result = False
    if vsc(8, [2, file_id]) == 0:
        if count==0:
            count = get_sectors()
        result = smart_write_data(vsctype.super_buffer, 0, count)
    elif vsctype.ext_err == 0x3603 or vsctype.ext_err == 0x3712:
        result = pwrfl(file_id, 0, count)
    return result

def prdfl(file_id, offset=0, count=0):
    result = False
    vsctype.super_buffer.clear()
    if count == 0:
        if prdfl(file_id, 0, 1):
            count = struct.unpack_from('@H', vsctype.super_buffer, 0xA)[0]
            vsctype.super_buffer.clear()
    vsctype.super_buffer = bytearray(count * 512)
    total = count - offset
    if total <= 256:
        if vsc(8, [13, file_id, offset, 0, 0, 0, count]) == 0:
            result = smart_read_data(vsctype.super_buffer, offset*512, count)
    else:
        while total > 0:
            single = 256 if total > 256 else total
            if vsc(8, [13, file_id, offset, 0, 0, 0, single]) != 0:
                break
            result = smart_read_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            total -= 256
    return result

def pwrfl(file_id, offset=0, count=0):
    result = False
    if count == 0:
        count = len(vsctype.super_buffer) // 512
    total = count - offset
    if total <= 256:
        if vsc(8, [14, file_id, offset, 0, 0, 0, count]) == 0:
            result = smart_write_data(vsctype.super_buffer, offset*512, count)
    else:
        while total > 0:
            single = 256 if total > 256 else total
            if vsc(8, [14, file_id, offset, 0, 0, 0, single]) != 0:
                break
            result = smart_write_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            total -= 256
    return result

def psrdfl(file_id, copy_id, offset, count):
    result = False
    vsctype.super_buffer = bytearray(count * 512)
    total = count - offset
    if total <= 256:
        if vsc(8, [17, file_id, offset, 0, 0, copy_id, count]) == 0:
            result = smart_read_data(vsctype.super_buffer, offset*512, count)
    else:
        while total > 0:
            single = 256 if total > 256 else total
            if vsc(8, [17, file_id, offset, 0, 0, copy_id, single]) != 0:
                break
            result = smart_read_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            total -= 256
    return result

def pswrfl(file_id, copy_id, offset, count):
    result = False
    total = count - offset
    if total <= 256:
        if vsc(8, [18, file_id, offset, 0, 0, copy_id, count]) == 0:
            result = smart_write_data(vsctype.super_buffer, offset*512, count)
    else:
        while total > 0:
            single = 256 if total > 256 else total
            if vsc(8, [18, file_id, offset, 0, 0, copy_id, single]) != 0:
                break
            result = smart_write_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            total -= 256
    return result

def rdlba(start_lba, region, count):
    result = False
    action_code = AC_RDWRRSVDLBA
    func_code = FC_RWLBA.eRDRLBA.value
    vsctype.super_buffer = bytearray(count * 512)
    if count <= 256:
        param_list = [
            func_code,
            start_lba & 0xFFFF,
            start_lba >> 16,
            region,
            count & 0xFFFF,
            count >> 16
        ]
        if vsc(action_code, param_list) == 0:
            result = smart_read_data(vsctype.super_buffer, 0, count)
    else:
        offset = 0
        while count > 0:
            single = 256 if count > 256 else count
            param_list = [
                func_code,
                start_lba & 0xFFFF,
                start_lba >> 16,
                region,
                single & 0xFFFF,
                single >> 16
            ]
            if vsc(action_code, param_list) != 0:
                break
            result =  smart_read_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            count -= 256
    return result

def wrlba(start_lba, region, count):
    result = False
    action_code = AC_RDWRRSVDLBA
    func_code = FC_RWLBA.eWRRLBA.value
    if count <= 256:
        param_list = [
            func_code,
            start_lba & 0xFFFF,
            start_lba >> 16,
            region,
            count & 0xFFFF,
            count >> 16
        ]
        if vsc(action_code, param_list) == 0:
           result = smart_write_data(vsctype.super_buffer, 0, count)
    else:
        offset = 0
        while count > 0:
            single = 256 if count > 256 else count
            param_list = [
                func_code,
                start_lba & 0xFFFF,
                start_lba >> 16,
                region,
                single & 0xFFFF,
                single >> 16
            ]
            if vsc(action_code, param_list) != 0:
                break
            result = smart_write_data(vsctype.super_buffer, offset*512, single)
            if not result:
                break
            offset += single
            count -= 256
    return result

# Read Verify Reseved LBA
def rvlba(start_lba, region, count):
    action_code = AC_RDWRRSVDLBA
    func_code = FC_RWLBA.eVfyRLBA.value
    param_list = [
        func_code,
        start_lba & 0xFFFF,
        start_lba >> 16,
        region,
        count & 0xFFFF,
        count >> 16
    ]
    return vsc(action_code, param_list)

# rdmtbl (Read memory table)
#
# Input:
#    Parmeter 1 (Table number)
#    101 = Servo WCS Table
#    102 = Servo Parameters Table
#    103 = Data Parameters Table
#    104 = Preamp Parameters Table
#    105 = MR Jog Table
#    106 = Tonescan table
#    107 = MNP parameter table
#    108 = DFH parameter table
def rdmtbl(table_no, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eRDMEMTABLE.value
    param_list = [
        func_code,
        table_no,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def wrmtbl(table_no, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eWRMEMTABLE.value
    param_list = [
        func_code,
        table_no,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def read_mem_tbl(table_no):
    if rdmtbl(table_no, 0, 0) != 0:
        return False
    count = get_sectors()
    vsctype.super_buffer = bytearray(count * 512)
    if not smart_read_data(vsctype.super_buffer, 0, count):
        return False
    return rstat_bitclr(0)

def write_mem_tbl(table_no, buffer):
    if wrmtbl(table_no, 0, 0) != 0:
        return False
    #count = len(buffer) // 512
    count = get_sectors()
    if not smart_write_data(buffer, 0, count):
        return False
    return rstat_bitclr(0)

# rddrmgrp (Read memory table - DRM Group Counters)
#
# Input:
#    Parmeter 1 (DRM Group number)
#          1 = Servo Spindle Error Counters
#          2 = Servo Actuator Error Counters
def rddrmgrp(drm_group_no, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eRDDRMGROUP.value
    param_list = [
        func_code,
        drm_group_no,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def wrdrmgrp(drm_group_no, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eWRDRMGROU.value
    param_list = [
        func_code,
        drm_group_no,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def read_drm_grp(drm_group_no):
    if rddrmgrp(drm_group_no, 0, 0) != 0:
        return False
    count = get_sectors()
    vsctype.super_buffer = bytearray(count * 512)
    if not smart_read_data(vsctype.super_buffer, 0, count):
        return False
    return rstat_bitclr(0)

def write_drm_grp(drm_group_no, buffer):
    if wrdrmgrp(drm_group_no, 0, 0) != 0:
        return False
    #count = len(buffer) // 512
    count = get_sectors()
    if not smart_write_data(buffer, 0, count):
        return False
    return rstat_bitclr(0)

# addprdlog (add period log counters)
#
# Input:
#    Parmeter 1 (DRM group id for which to add period logs)
#    Parmeter 2 (offset from which to start the sum)
#    Parameter 3 (size of each counter to add)
#    Parameter 4 (Number of counters to add)
# Output:
#       period log sum each 8 bytes in rbfr.
def addprdlog(drm_group_id, offset, size, count):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.ePERIODLOGSUM.value
    param_list = [
        func_code,
        drm_group_id,
        offset,
        size,
        count,
    ]
    return vsc(action_code, param_list)

def rdstfl(file_id, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eRDSTATICFILE.value
    param_list = [
        func_code,
        file_id,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def wrstfl(file_id, offset=0, numbytes=0):
    action_code = AC_RDWRMTBL
    func_code = FC_RWMemTbl.eWRSTATICFILE.value
    param_list = [
        func_code,
        file_id,
        offset,
        numbytes,
    ]
    return vsc(action_code, param_list)

def read_static_file(file_id):
    if rdstfl(file_id, 0, 0) != 0:
        return False
    count = get_sectors()
    vsctype.super_buffer = bytearray(count * 512)
    if not smart_read_data(vsctype.super_buffer, 0, count):
        return False
    return rstat_bitclr(0)

def write_static_file(file_id, buffer):
    if wrstfl(file_id, 0, 0) != 0:
        return False
    #count = len(buffer) // 512
    count = get_sectors()
    if not smart_write_data(buffer, 0, count):
        return False
    return rstat_bitclr(0)

def rdchs(cyl, hd, sec, blk):
    action_code = AC_RDWRCHS
    func_code = FC_RWCHS.eRDCHS_WITHRELO.value
    param_list = [
        func_code,
        cyl & 0xFFFF,
        cyl >> 16,
        hd,
        sec,
        blk & 0xFFFF,
        blk >> 16
    ]
    return vsc(action_code, param_list)

def wrchs(cyl, hd, sec, blk):
    action_code = AC_RDWRCHS
    func_code = FC_RWCHS.eWRCHS_WITHRELO.value
    param_list = [
        func_code,
        cyl & 0xFFFF,
        cyl >> 16,
        hd,
        sec,
        blk & 0xFFFF,
        blk >> 16
    ]
    return vsc(action_code, param_list)

def read_track(cyl, hd):
    spt = get_phys_zone_spt(hd)
    if spt == 0:
        return False
    if rdchs(cyl, hd, 1, spt) != 0:
        return False
    vsctype.super_buffer = bytearray(spt * 512)
    if not smart_read_data(vsctype.super_buffer, 0, spt):
        return False
    return rstat_bitclr(0)

def write_track(cyl, hd, filename):
    spt = get_phys_zone_spt(hd)
    if spt == 0:
        return False
    buffer = bytearray()
    if not read_file(filename, buffer):
        return False
    if wrchs(cyl, hd, 1, spt) != 0:
        return False
    if not smart_write_data(buffer, 0, spt):
        return False
    return rstat_bitclr(0)

def clrcyl(cyl, hd):
    spt = get_phys_zone_spt(hd)
    if spt == 0:
        return False
    if wrchs(cyl, hd, 1, spt) != 0:
        return False
    vsctype.super_buffer = bytearray(spt * 512)
    if not smart_write_data(vsctype.super_buffer, 0, spt):
        return False
    return rstat_bitclr(0)

def clr_res_cyl(blk=0):
    vir_hd_cnt = get_vir_hd()
    if vir_hd_cnt < 1:
        return
    #pys_zone_tbl_hdr, pys_zone_tbl = get_phys_zone_tbl(0)
    pys_zone_tbl = get_phys_zone_tbl(0)[1]
    if pys_zone_tbl == []:
        return
    first_cyl_zn = pys_zone_tbl[0].first_cyl_zn
    last_cyl_zn  = pys_zone_tbl[0].last_cyl_zn if blk == 0 else blk
    spt_hd0_zn   = pys_zone_tbl[0].spt_hd0_zn
    for c in range(last_cyl_zn, first_cyl_zn-1, -1):
        clrcyl(c, 0)
    if vir_hd_cnt == 1:
        return
    for c in range(last_cyl_zn, first_cyl_zn-1, -1):
        clrcyl(c, 1)

def flashr(start_offset, bytes_cnt):
    action_code = AC_RWERASEFLASH
    func_code = FC_Flash.eRdFlash.value
    param_list = [
        func_code,
        start_offset & 0xFFFF,
        start_offset >> 16,
        bytes_cnt & 0xFFFF,
        bytes_cnt >> 16
    ]
    return vsc(action_code, param_list)

def flashw(start_offset, bytes_cnt):
    action_code = AC_RWERASEFLASH
    func_code = FC_Flash.eWrFlash.value
    param_list = [
        func_code,
        start_offset & 0xFFFF,
        start_offset >> 16,
        bytes_cnt & 0xFFFF,
        bytes_cnt >> 16
    ]
    return vsc(action_code, param_list)

def flashe(start_offset, bytes_cnt):
    action_code = AC_RWERASEFLASH
    func_code = FC_Flash.eEraseFlash.value
    param_list = [
        func_code,
        start_offset & 0xFFFF,
        start_offset >> 16,
        bytes_cnt & 0xFFFF,
        bytes_cnt >> 16
    ]
    return vsc(action_code, param_list)

def read_flash(filename):
    drv_data_tbl = Drv_Data_Tbl()
    if not get_drv_tbl_data(drv_data_tbl):
        return False
    num_bytes = drv_data_tbl.FlashSize * 16 * 1024
    if flashr(0, 0) != 0:
        return False
    buffer = bytearray(num_bytes)
    if not smart_read_data(buffer, 0, num_bytes // 512):
        return False
    return rstat_bitclr(0) and save_file(filename, buffer)

def write_flash(filename):
    drv_data_tbl = Drv_Data_Tbl()
    if not get_drv_tbl_data(drv_data_tbl):
        return False
    num_bytes = drv_data_tbl.FlashSize * 16 * 1024
    buffer = bytearray()
    if not read_file(filename, buffer):
        return False
    if buffer[0] != 0x5A or len(buffer) != num_bytes:
        return False
    if flashe(0, 0) != 0:
        return False
    if flashw(0, 0) != 0:
        return False
    if not smart_write_data(buffer, 0, num_bytes // 512):
        return False
    return rstat_bitclr(0)

def get_file_entry(file_id=1):
    entry_list = []
    if rdfl(file_id):
        buffer = c_buffer(bytes(vsctype.super_buffer))
        file_header_size = vsctype.super_buffer[6]
        entry_cnt = struct.unpack_from('@H', vsctype.super_buffer, file_header_size)[0]
        entry_start = file_header_size + 2
        if file_id != 1:
            entry_cnt = vsctype.super_buffer[file_header_size]
            entry_start = file_header_size + 1
        for i in range(entry_cnt):
            if vsctype.super_buffer[entry_start] != 0 and vsctype.super_buffer[entry_start] != 255:
                entry_size = vsctype.super_buffer[entry_start]
            file_entry = File_Entry()
            memmove(byref(file_entry), byref(buffer, entry_start), sizeof(file_entry))
            entry_list.append(file_entry)
            entry_start += entry_size
    return entry_list

def get_flash_entry(file_id=0xB):
    return get_file_entry(file_id)

def get_res_entry(file_id=1):
    return get_file_entry(file_id)

def get_rrt_entry(file_id=0xB):
    rrt = Reserve_Region_Table_Header()
    entry_list = []
    if rdfl(file_id):
        buffer = c_buffer(bytes(vsctype.super_buffer))
        file_header_size = vsctype.super_buffer[6]
        entry_cnt = vsctype.super_buffer[file_header_size]
        entry_start = file_header_size + 1
        for i in range(entry_cnt):
            if vsctype.super_buffer[entry_start] != 0:
                entry_size = vsctype.super_buffer[entry_start]
            entry_start += entry_size
        memmove(byref(rrt), byref(buffer, entry_start), sizeof(rrt))
        entry_start += 5
        for i in range(rrt.num_regions):
            region_entry = Reserve_Region_Entry()
            memmove(byref(region_entry), byref(buffer, entry_start), sizeof(region_entry))
            entry_list.append(region_entry)
            entry_start += 8
    return rrt, entry_list

def init_rrt(file_id=0xB):
    rrt = Reserve_Region_Table_Header()
    entry_list = []
    if not rdfl(file_id):
        return False
    buffer = c_buffer(bytes(vsctype.super_buffer))
    file_header_size = vsctype.super_buffer[6]
    entry_cnt = vsctype.super_buffer[file_header_size]
    entry_start = file_header_size + 1
    for i in range(entry_cnt):
        if vsctype.super_buffer[entry_start] != 0:
            entry_size = vsctype.super_buffer[entry_start]
        entry_start += entry_size
    memmove(byref(rrt), byref(buffer, entry_start), sizeof(rrt))
    entry_start += 5
    buffer = bytearray(8)
    vsctype.super_buffer[0x29:0x31] = buffer[0:8]
    vsctype.super_buffer[0x1B] = 0
    for i in range(rrt.num_regions):
        entry_start += 4
        vsctype.super_buffer[entry_start:entry_start+4] = buffer[0:4]
        entry_start += 4
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(file_id):
        return False
    return rstat_bitclr(0)

def init_region():
    init_rrt()
    file_entry = File_Entry()
    entry_list = get_flash_entry()
    if file_find(0x20B, file_entry, entry_list):
        init_rrt(0x20B)

def file_create(file_id, mask_bits, sector_count):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eCreateFile.value
    key_sector.param2 = file_id
    key_sector.param3 = mask_bits & 0xFFFF
    key_sector.param4 = mask_bits >> 16
    key_sector.param5 = sector_count
    return send_vsc(key_sector)

def file_delete(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eDeleteRemoveFile.value
    key_sector.param2 = file_id
    return send_vsc(key_sector)

def file_mark_bad(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eMarkFileBad.value
    key_sector.param2 = file_id
    return send_vsc(key_sector)

def file_get_attribs(file_id):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eReturnAttribs.value
    key_sector.param2 = file_id
    return send_vsc(key_sector)

def file_set_attribs(file_id, mask_bits):
    key_sector = Key_Sector()
    key_sector.action_code = AC_RDWRRESFILE
    key_sector.param1 = FC_RWResFile.eSetAttribs.value
    key_sector.param2 = file_id
    key_sector.param3 = mask_bits & 0xFFFF
    key_sector.param4 = mask_bits >> 16
    return send_vsc(key_sector)

def file_defrag():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FILEMGR
    key_sector.param1 = FC_FileMgr.eDefragment.value
    return send_vsc(key_sector)

def clr_drm_log(agent_code):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eClearDRMLog.value
    key_sector.param3 = agent_code
    return send_vsc(key_sector)

def clr_drm_section(section_code):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eClrDRMSection.value
    key_sector.param3 = section_code
    return send_vsc(key_sector)

def clr_factory_file():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eClearFactoryFile.value
    return send_vsc(key_sector)

def init_odtaaws():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eInitODTAAWS.value
    return send_vsc(key_sector)

def init_mrr():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eMeasureMRResistance.value
    return send_vsc(key_sector)

def init_rro():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eInitRRO.value
    return send_vsc(key_sector)

# Clear debug stop in ram and file 0x2D
def clr_dbs_all():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eClrDebugStop.value
    key_sector.param3 = FC_ClearDebugStop.eClrDBSAll.value
    return send_vsc(key_sector)

# Clear debug stop in memory only
def clr_dbs_ram():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eClrDebugStop.value
    key_sector.param3 = FC_ClearDebugStop.eClrDBSRam.value
    return send_vsc(key_sector)

def rst_err_rate():
    key_sector = Key_Sector()
    key_sector.action_code = AC_ERATETBL
    key_sector.param1 = FC_ErrRateTbl.eResetErate.value
    return send_vsc(key_sector)

def set_pst_mode(code=1):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.ePSTMode.value
    key_sector.param3 = code
    return send_vsc(key_sector)

def set_smart_status(attr_id, value):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FEATCTRL
    key_sector.param1 = SET_FEATURE
    key_sector.param2 = FC_FeatureCtrl.eSmartAttributeIdNewValue.value
    key_sector.param3 = attr_id
    key_sector.param3 = value
    return send_vsc(key_sector)

def clr_smart():
    return clr_drm_log(46)

def file_find(file_id, file_entry, entry_list):
    file_exist = False
    for file_entry in entry_list:
        if file_entry.FileID == file_id:
            file_exist = True
            break
    return file_exist

def file_rebuild(file_id):
    file_entry = File_Entry()
    entry_list = get_res_entry()
    if not file_find(file_id, file_entry, entry_list):
        return False
    if not file_delete(file_id):
        return False
    if not file_create(file_id, file_entry.FileAttrib, file_entry.FileSize):
        return False
    if not warm_start():
        return False
    if not wait_not_busy(30):
        return False
    return clr_drm_log(1)

def file_zero(file_id):
    if not rdfl(file_id, 1):
        return False
    file_hdr_size = vsctype.super_buffer[6]
    buffer = bytearray(file_hdr_size)
    copy_bytes(buffer, vsctype.super_buffer, file_hdr_size)
    count = struct.unpack_from('@H', vsctype.super_buffer, 10)[0]
    vsctype.super_buffer.clear()
    vsctype.super_buffer = bytearray(count * 512)
    copy_bytes(vsctype.super_buffer, buffer, file_hdr_size)
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(file_id, count):
        return False
    return rstat_bitclr(0)

def zero_size(file_id):
    if not rdfl(file_id):
        return False
    vsctype.super_buffer[10] = 0
    vsctype.super_buffer[11] = 0
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(file_id):
        return False
    return rstat_bitclr(0)

def fix_size(file_id):
    if not rdfl(file_id):
        return False
    count = len(vsctype.super_buffer) // 512
    vsctype.super_buffer[10] = count >> 8
    vsctype.super_buffer[11] = count & 0xFF
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(file_id):
        return False
    return rstat_bitclr(0)

def init2(on=True):
    if not rdfl(0x12):
        return False
    if on:
        count = len(vsctype.super_buffer) // 512
        vsctype.super_buffer[10] = count >> 8
        vsctype.super_buffer[11] = count & 0xFF
    else:
        vsctype.super_buffer[10] = 0
        vsctype.super_buffer[11] = 0
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(0x12):
        return False
    return rstat_bitclr(0)

def unlock():
    #result = file_zero(0xD)
    file_entry = File_Entry()
    entry_list = get_flash_entry()
    if file_find(0x20B, file_entry, entry_list):
        if not rdfl(0x20B):
            return False
        vsctype.super_buffer[9] = 0
        if not write_static_file(0xB, vsctype.super_buffer):
            return False
        #result = file_zero(0xD)
    return file_zero(0xD)

def init_adp():
    if not rdfl(0x41):
        return False
    vsctype.super_buffer[9] = 0x40
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(0x40):
        return False
    return rstat_bitclr(0)

def init_config():
    file_id = 0x12
    file_entry = File_Entry()
    entry_list = get_res_entry()
    if file_find(0x12, file_entry, entry_list):
        if not zero_size(0x12):
            return False
    else:
        file_id = 0x411
        if not zero_size(0x411):
            return False
    if not spindown_reset():
        return False
    if not wait_not_busy(30):
        return False
    if not read_static_file(2):
        return False
    feature_control_offset = struct.unpack_from('@H', vsctype.super_buffer, 58)[0]
    vsctype.super_buffer[feature_control_offset + 12] = 6
    read_channel_config_offset = struct.unpack_from('@H', vsctype.super_buffer, 86)[0]
    read_channel_config_size   = struct.unpack_from('@H', vsctype.super_buffer, 88)[0]
    offset = read_channel_config_offset + read_channel_config_size - 1
    vsctype.super_buffer[offset] = 1
    royl_checksum32(vsctype.super_buffer)
    if not wrfl(2):
        return False
    return fix_size(file_id)

def clr_abort_section():
    if not rdfl(0xE6):
        return False
    for i in range(16):
        vsctype.super_buffer[0x400 + i] = 0
    if not wrfl(0xE6):
        return False
    return rstat_bitclr(0)

def fmt_select_get_current():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 1
    return send_vsc(key_sector)

def fmt_select_get_dcm():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 2
    return send_vsc(key_sector)

def fmt_select_get_tpi():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 3
    return send_vsc(key_sector)

def fmt_select_get_capacity():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 4
    return send_vsc(key_sector)

def fmt_select_set_dcm(dcm=1, fmt_type=0):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT if fmt_type == 0 else 0x72
    key_sector.param1 = 5 if fmt_type == 0 else 1
    key_sector.param2 = dcm
    return send_vsc(key_sector)

def fmt_select_set_target_capacity(targ_capacity, fmt_type=0):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT if fmt_type == 0 else 0x72
    key_sector.param1 = 6 if fmt_type == 0 else 2
    key_sector.param2 = 0 if fmt_type == 0 else targ_capacity
    key_sector.param3 = targ_capacity if fmt_type == 0 else 0
    return send_vsc(key_sector)

def fmt_select_set_hq_capacity(hq_capacity, fmt_type=0):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT if fmt_type == 0 else 0x72
    key_sector.param1 = 7 if fmt_type == 0 else 3
    key_sector.param2 = 0 if fmt_type == 0 else hq_capacity
    key_sector.param3 = hq_capacity if fmt_type == 0 else 0
    return send_vsc(key_sector)

def fmt_select_set_tpi(tpi0, tpi1, tpi2, tpi3, tpi4, tpi5, tpi6, tpi7):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 8
    key_sector.param4 = tpi0
    key_sector.param5 = tpi1
    key_sector.param6 = tpi2
    key_sector.param7 = tpi3
    key_sector.param8 = tpi4
    key_sector.param9 = tpi5
    key_sector.param10= tpi6
    key_sector.param11= tpi7
    return send_vsc(key_sector)

def fmt_select_set_capacity(cap0, cap1, cap2, cap3, cap4, cap5, cap6, cap7):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 9
    key_sector.param4 = cap0
    key_sector.param5 = cap1
    key_sector.param6 = cap2
    key_sector.param7 = cap3
    key_sector.param8 = cap4
    key_sector.param9 = cap5
    key_sector.param10= cap6
    key_sector.param11= cap7
    return send_vsc(key_sector)

def fmt_select_get_capacity_groups():
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTSELECT
    key_sector.param1 = 12
    return send_vsc(key_sector)

#fprint "\n\nFormat Unit Options:\n"
#fprint "\n  bit 0 - Ignore PList"
#fprint "\n  bit 1 - Ignore GList"
#fprint "\n  bit 2 - Post current Cyl to Task File"
#fprint "\n  bit 3 - IBI mode (PList MUST be in RAM)"
#fprint "\n  bit 4 - Skip write of all LBAs"
#fprint "\n  bit 5 - Quick LBA write of bad trk. Overide bit 4 (SOC only)"
#fprint "\n  bit 6 - Generate defect mgt table in memory, do not write to Disk (SOC only)
def fmt_unit(option=1):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTUNIT
    key_sector.param1 = FC_FmtUnit.eFMTUNIT.value
    key_sector.param2 = option
    return send_vsc(key_sector)

# Format Reserved Unit. User needs to set b and placed reserved list in rbfr.
def fmt_reserved(fsize):
    key_sector = Key_Sector()
    key_sector.action_code = AC_FMTUNIT
    key_sector.param1 = FC_FmtUnit.eFMTRESERVED.value
    key_sector.param2 = 0
    key_sector.param3 = fsize    # File size of rplist in sectors
    return send_vsc(key_sector)
